# 打开网页
import os
import time
import traceback
from pathlib import Path

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, StaleElementReferenceException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

from tools import *


# 指定 chromedriver 路径


def init_browser(driver_path):
    # 设置 Chrome 参数
    options = Options()

    options.page_load_strategy = 'eager'  # 只等待 DOMContentLoaded，不等页面完全加载

    options.add_argument("--disable-blink-features=AutomationControlled")  # 防检测

    options.add_argument('--disable-extensions')

    options.add_argument('--no-sandbox')

    options.add_argument('--disable-dev-shm-usage')

    options.add_argument('--disable-gpu')

    options.add_argument('--enable-unsafe-swiftshader')  #

    # options.add_argument('--disable-software-rasterizer')  # 可选辅助关闭警告

    # # 禁止图片和css加载  禁用后验证码无法通过
    # prefs = {"profile.managed_default_content_settings.images": 2, 'permissions.default.stylesheet': 2}
    # options.add_experimental_option("prefs", prefs)
    # options.add_argument('--disable-images')  # 可配合 Chrome 插件或 DevTools 限制加载图片

    options.add_experimental_option("excludeSwitches", ["enable-logging"])  # 关闭警告
    options.add_experimental_option("excludeSwitches", ["enable-automation"])  # 防止出现“Chrome正在受到自动测试软件的控制”
    options.add_experimental_option("useAutomationExtension", False)  # 禁用扩展

    # 可选：无头模式（不显示浏览器）
    # 使用无头模式  过去验证码后得到的Cookie不能使用
    # options.add_argument("--headless")
    # 启动 driver
    service = Service(driver_path)
    driver = webdriver.Chrome(service=service, options=options)

    # 执行 JavaScript 删除 navigator.webdriver 特征值
    driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        "source": """
                Object.defineProperty(navigator, 'webdriver', {
                    get: () => undefined
                });
            """
    })
    return driver


def set_cookie(driver, cookies):
    for cookie in cookies:
        selenium_cookie = {
            'name': cookie.name,
            'value': cookie.value,
            'domain': cookie.domain,  # 如果报错，可删掉这个字段试试
            'path': cookie.path,
        }
        try:
            driver.add_cookie(selenium_cookie)
        except Exception as e:
            print(f"添加 cookie 出错: {e}, cookie={selenium_cookie}")


def bypass_selenium(cookies, driver):
    time.sleep(1)
    # set_cookie(driver, cookies)
    # driver.get("https://www.smzdm.com/jingxuan/")
    try:
        driver.switch_to.frame(0)
        """
        JS方式
        """
        # 下载背景图
        p1 = download_slider_bg(driver, "#slideBg", OTHER_PATH + 'img1.png')
        # 下载滑块图
        p2 = download_slider_bg(driver, "#tcOperation > div:nth-child(7)", OTHER_PATH + "img2.png")
        # print(f"滑块应该移动到的位置 x = {x}")
        p2 = crop_and_save(p2, (130, 480), (270, 630), OTHER_PATH + "cropped.png")
        # TODO 获取时间  将图片保存为图片，便于判断滑块是否正确通过
        x = detect_displacement(p2, p1, save_path=OTHER_PATH + "marked_gap.png")
        if not x:
            print("未找到缺口位置")
        else:
            # 可模拟点击、拖动等操作
            res = drag_captcha_by_js(driver, x)

        time.sleep(0.5)
        driver.save_screenshot(OTHER_PATH + "full_page.png")  # 保存截图到当前目录
        if "崩溃啦" in driver.page_source:
            time.sleep(1)
            driver.refresh()
            time.sleep(1)

    except Exception as e:
        # print("发生异常:", e)
        traceback.print_exc("发生异常")
    finally:
        driver.switch_to.default_content()
        print("滑块模拟结束")
        time.sleep(2)
        print("新的cookie => ", driver.get_cookies())
        return driver.get_cookies()

def get_category_value(driver):
    """从商品链接中提取类别信息"""
    result_lis = []
    for i in driver.find_elements(By.XPATH, '//*[@id="feed-wrap"]/div/a[position()>1]/span'):
        result_lis.append(i.text.replace(r"/", "&"))

    while (len(result_lis) < 4):
        result_lis.append("无")
    if result_lis:
        return "/".join(result_lis)
    else:
        return None

def query(driver, ori_text, retry_count=0, pre_url=""):
    try:
        time.sleep(3)
        # 验证码检测
        if "2s后自动为您刷新验证码" in driver.page_source:
            print("出现验证码，分类", ori_text)
            bypass_selenium({}, driver)
            if retry_count < 3:
                return query(driver, ori_text, retry_count + 1)
            else:
                print("重试次数过多，跳过")
                return None, driver.current_url

        # 搜索框
        search_input = WebDriverWait(driver, 5).until(
            EC.element_to_be_clickable((By.CLASS_NAME, "search-input")))

        # 查询按钮
        search_button = WebDriverWait(driver, 5).until(
            EC.element_to_be_clickable((By.CLASS_NAME, "search-submit")))

        search_input.click()
        time.sleep(0.5)
        search_input.clear()
        time.sleep(0.5)
        search_input.send_keys(ori_text)
        time.sleep(0.5)
        search_button.click()

        # 等待搜索页面加载完成
        WebDriverWait(driver, 15).until(lambda d: d.current_url != pre_url)
        time.sleep(0.5)

        # //*[@id="feed-main-list"]/li[1]

        # 等待元素出现后提取url
        first_url = driver.find_element(By.XPATH, '//*[@id="feed-main-list"]/li[1]/div/div/a').get_attribute("href")

        # 提取url
        if not first_url:
            print("未找到元素")
            return None, driver.current_url

        driver.get(first_url)

        # 等待类目数据加载出来
        WebDriverWait(driver, 15).until(
            EC.element_to_be_clickable((By.XPATH, '//*[@id="feed-wrap"]/div/a[position()>1]/span')))
        time.sleep(0.5)

        category_value = get_category_value(driver)

        if not category_value:
            print("未找到元素")
            return None, driver.current_url
        else:
            return category_value, driver.current_url

    except TimeoutException:
        print(f"未获取到类别信息 => {ori_text}")
        driver.refresh()
        return None, driver.current_url
    except StaleElementReferenceException:
        print("元素失效，重试获取...")
        driver.refresh()
        if retry_count < 3:
            return query(driver, ori_text, retry_count + 1)
        else:
            print("重试次数过多，跳过")
            return None, driver.current_url
    except Exception as e:
        print(f"位置2 查询“{ori_text}”时发生错误：{str(e)[:200]}")

        # traceback.print_exc()
        return None, driver.current_url


DRIVER = init_browser(Path.cwd() / DRIVER_PATH)

if __name__ == '__main__':
    # 从数据库读取 error 为 1 的记录
    table = "category_mapping"

    # sql = f"-- SELECT original_name FROM {table} WHERE error = 1 AND standard_name IS NULL"
    # sql = f"SELECT original_name FROM {table} WHERE error = 1 OR multiple_flag = 1"
    sql = f"SELECT original_name FROM {table} WHERE error = 1"

    DRIVER.get("https://www.smzdm.com/")
    pre_url = ""
    while True:
        try:
            # 避免太频繁执行sql查询 很浪费性能
            time.sleep(1.5)
            cursor.execute(sql)

            data = cursor.fetchone()
            if not data: continue

            ori_category = data[0]
            if "、"in ori_category:
                last_value = ori_category.split("、")[-1]
            elif("\\"in ori_category):
                last_value = ori_category.split("\\")[-1]
            else:
                last_value = ori_category.split("/")[-1]

            standard_category, pre_url = query(DRIVER, last_value, pre_url=pre_url)

            # 将提取后的类别信息推送至数据库
            if standard_category:
                print("【待映射 原类目：】", ori_category, "【映射后 值得买类目：】", standard_category)
                cursor.execute(
                    f"UPDATE  {table} SET standard_name = %s,multiple_flag = %s,error = %s WHERE original_name = %s",
                    (standard_category, 0, 0, ori_category)
                )
                conn.commit()
            else:
                # 标记为  selenium 查询品牌也出错的状态 与2相或之后存入数据库记录
                cursor.execute(
                    f"UPDATE  {table} SET error = {3} WHERE original_name = %s",
                    (ori_category)
                )
                # print("已记录至数据库,并更新错误代码")
                conn.commit()
        except KeyboardInterrupt:
            os._exit(0)
        except Exception as e:
            print(f"位置1 查询{data}出错=>{str(e)[:200]}",)
            # traceback.print_exc()
            # DRIVER.refresh()
            continue
